home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-01-15 | 39.5 KB | 1,411 lines | [TEXT/MPS ] |
- /*
- File: EntryPoints.c
-
- Contains: This file contains the structures necessary for the STREAMS environment
- and also the routines that are not hardware dependent.
-
- Written by:
-
- Copyright: © 1994, 1996-1997 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <FW12> 3/18/97 ES Changed protocol driver description version to final.
- <FW11> 2/20/97 ES Changed FWClientAsynchRequestParams buffer field to
- receiveBuffer.
- <FW10> 1/9/97 ES Took out some debugging stuff. Removed fixed address allocation.
- <FW9> 12/27/96 ES Changed to connect and disconnect target units one at a time.
- <FW8> 12/27/96 ES Changed a bunch of "FWDriver"s to "FWClient"s. Changed to
- protocol driver.
- <FW7> 12/16/96 ES Changed to work with new read/write/lock request/complete
- processing mechanism.
- <FW6> 9/16/96 ES Changed FireWire driver interface procs to return command
- acceptance.
- <FW5> 8/29/96 ES Changed FWRegisterDriver to take driver interface proc table.
- <FW4> 8/16/96 ES Changed FWDriverInterface to call FWDriverCommandIsComplete.
- <FW3> 8/1/96 ES Took out unused local variables.
- <FW2> 4/15/96 ES Update for use with Driver Notification services.
- <FW1> 3/27/96 ES first checked in
-
- To Do:
- */
-
-
- //-----------------------------------------------------------------------------------------
- // Header files
- //-----------------------------------------------------------------------------------------
-
- #include <OpenTptModule.h> // Open Transport files
- #include <OpenTptPCISupport.h>
- #include <OpenTptDevLinks.h>
- #include <OpenTptLinks.h>
- #include <miioccom.h>
- #include <stropts.h>
- #include <dlpi.h>
-
- #include <Kernel.h> // System files
- #include <DriverServices.h>
- #include <Devices.h>
- #include <CodeFragments.h>
- #include <Interrupts.h>
- #include <FireWire.h>
-
- #include "EntryPoints.h" // our files
- #include "DLPIRoutines.h"
- #include "HWSpecific.h"
- /*zzz*/
- static char debugStr[256];
- /*zzz*/
-
- //-----------------------------------------------------------------------------------------
- // STREAMS Structures
- //-----------------------------------------------------------------------------------------
-
- static struct module_info moduleInformation =
- {
- kEnetModuleID, // indicates this dlpi is ethernet
- kModuleDeviceInfoName,
- 0, // minimum packet data size
- kMaxTransmitSize, // maximum packet data size
- 6000, // hi water mark
- 5000 // low water mark
- };
-
- static struct qinit readSide =
- {
- putq,
- NULL,
- OpenServiceRoutine,
- CloseServiceRoutine,
- NULL, // reserved for future use
- &moduleInformation,
- NULL // no module_stat structure
- };
-
-
- static struct qinit writeSide =
- {
- WritePutRoutine,
- WriteServiceRoutine,
- NULL, // no module open needed for write side
- NULL, // no module close needed for write side
- NULL, // reserved for future use
- &moduleInformation,
- NULL // no module_stat structure
- };
-
-
- static struct streamtab streamTabInformation =
- {
- &readSide,
- &writeSide,
- NULL, // lower read/write qinit (multiplexors only)
- NULL
- };
-
- static struct install_info theInstallInformation =
- {
- &streamTabInformation,
- kOTModIsDriver, // install flags
- SQLVL_MODULE, // Synchronization level
- 0, // Shared writer list buddy
- 0 // Flag - set to 0
- };
-
- //-----------------------------------------------------------------------------------------
- // Global variable for the entire CFM
- //-----------------------------------------------------------------------------------------
-
- DLPIPrivateData *gDLPIPrivateData = NULL; // private data for our dlpi driver
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This data stucture entry point is exported through the cfm mechanism. Information
- // about the hardware that this driver works with is located in this structure.
- //
- //-----------------------------------------------------------------------------------------
-
- enum
- {
- kFrameFlags = kOTFramingEthernet | kOTFramingEthernetIPX | kOTFraming8022
- };
-
- DriverDescription TheDriverDescription =
- {
- // Signature Info
- kTheDescriptionSignature, // signature always first
- kInitialDriverDescriptor, // version second
-
- // Type Info
- "\pFWOpenTransport", // Our name, module info name must match
- 1,0,finalStage,0, // Major, Minor, Stage, Rev
-
- // OS Runtime Info
- kDriverIsUnderExpertControl, // Runtime Options
- "\penet", // should be kEnetName
- 0,0,0,0,0,0,0,0, // reserve 8 longs
-
- // OS Service Info
- 1, // Number of Service Categories
- kServiceCategoryOpenTransport, // We support the 'otan' category
- OTPCIServiceType(kOTEthernetDevice,kFrameFlags,0,1),
- 1,0,0,0 // Major, Minor, Stage, Rev
- };
-
- FWPDriverDescription ThePDriverDescription =
- {
- kTheFWPDriverDescriptionSignature,
- kInitialFWPDriverDescriptor,
-
- kServiceCategoryFWDriver,
- 0,0,finalStage,0,
-
- 0,
- "\pFWOpenTransport"
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // FWClientWriteCompleteInterface
- //
- // FireWire client interface for handling completed write requests.
- //
-
- OSStatus FWClientWriteCompleteInterface(
- FWClientAsynchRequestParamsPtr
- pFWClientAsynchRequestParams,
- UInt32 *pCommandAcceptance)
- {
- DLPIPrivateData *pDLPIPrivateData;
- mblk_t *thePacket;
- UInt32 dataSize;
- OSStatus status = noErr;
-
- // Notify OpenTransport that we're processing in an interrupt.
- OTEnterInterrupt ();
-
- // Get our private data.
- pDLPIPrivateData = (DLPIPrivateData *)
- pFWClientAsynchRequestParams->pAddressSpecificData;
-
- // Pass on received packet in a message block.
- dataSize = pFWClientAsynchRequestParams->length;
- if ((thePacket = allocb (dataSize, BPRI_HI)) != NULL)
- {
- // Write received data into message block.
- bcopy (pFWClientAsynchRequestParams->receiveBuffer,
- thePacket->b_rptr,
- dataSize);
- thePacket->b_wptr += dataSize;
-
- // Put message block on queue, so callback routine can
- // dequeue it and pass it on to upper layers.
- EnqueueElement (&(pDLPIPrivateData->RxPacketQueue),
- (QElem *) thePacket,
- kNoInterrupts);
- OTScheduleDeferredTask (pDLPIPrivateData->RxDeferredTaskCookie);
- }
-
- // Complete FireWire client command.
- FWClientCommandIsComplete
- (pFWClientAsynchRequestParams->fwClientInterfaceParams.fwClientCommandID,
- status);
-
- // Return command acceptance.
- //zzz is this the right way? If we've completed the command, we can accept more.
- *pCommandAcceptance = kFWClientCommandAcceptNoMore;
-
- // Notify OpenTransport that we're done processing in an
- // interrupt.
- OTLeaveInterrupt ();
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // FWPDriverUnitAdded
- //
- // FireWire protocol driver interface for handling added units.
- //
-
- OSStatus FWPDriverUnitAdded(
- FWPDriverID fwPDriverID,
- UInt32 fwPDriverSpecificData,
- FWUnitID fwUnitID)
- {
- CSRROMEntryIterator csrROMIterator = kInvalidCSRROMIterator;
- CSRROMSearchCriteria searchCriteria;
- CSRROMEntryID unitCSRROMEntryID,
- unitInfoCSRROMEntryID = kInvalidCSRROMEntryID;
- UInt32 unitInfoSize;
- Boolean unitAdded;
- Boolean done;
- OSStatus status = noErr;
-
- // Set target unit.
- if (!gDLPIPrivateData->unitConnection)
- {
- gDLPIPrivateData->fwUnitID = fwUnitID;
- status = FWAddUnitConnection (fwUnitID, fwPDriverID);
- if (status == noErr)
- {
- gDLPIPrivateData->unitConnection = true;
- unitAdded = true;
- }
- }
- else
- {
- unitAdded = false;
- }
-
- // Get node's unit dependent information.
- if ((status == noErr) && (unitAdded))
- {
- // Get unit CSR ROM entry ID.
- status = FWGetUnitCSRROMEntryID ((FWReferenceID) gDLPIPrivateData->fwUnitID,
- &unitCSRROMEntryID);
-
- // Create a CSR ROM search iterator.
- if (status == noErr)
- {
- status = FWCSRROMCreateIterator (&csrROMIterator,
- (FWReferenceID) gDLPIPrivateData->fwUnitID);
- }
-
- // Set iterator to start searching at our unit directory.
- if (status == noErr)
- {
- status = FWCSRROMSetIterator (csrROMIterator,
- unitCSRROMEntryID,
- kIterateDescendants);
- }
-
- // Search for unit dependent info leaf.
- if (status == noErr)
- {
- searchCriteria.csrROMSearchType = kCSRROMSearchForKey;
- searchCriteria.keyType = kCSRLeafKeyTypeBit;
- searchCriteria.keyHi = 0;
- searchCriteria.keyLo = 1 << kCSRUnitDependentInfoKey;
- unitInfoSize = sizeof (FWAddress);
- status = FWCSRROMEntrySearch (csrROMIterator,
- kIterateContinue,
- &unitInfoCSRROMEntryID,
- &done,
- &searchCriteria,
- (Ptr) &(gDLPIPrivateData->targetAddress),
- &unitInfoSize);
- }
-
- // Clean up.
- if (csrROMIterator != kInvalidCSRROMIterator)
- FWCSRROMDisposeIterator (csrROMIterator);
- if (unitInfoCSRROMEntryID != kInvalidCSRROMEntryID)
- FWCSRROMDisposeEntryID (unitInfoCSRROMEntryID);
- }
-
- // Set up some resources for target.
- if ((status == noErr) && (unitAdded))
- {
- FWAllocateAsynchCommandObject (&(gDLPIPrivateData->asynchCommandObjectID));
- FWSetFWCommandParams (gDLPIPrivateData->asynchCommandObjectID,
- (FWReferenceID) gDLPIPrivateData->fwUnitID,
- 0,
- ABCVendorTransmitCompletion,
- 0);
- FWSetAsynchCommandMaxRetries (gDLPIPrivateData->asynchCommandObjectID, 8);
-
- FWSetMaxPayloadSize ((FWReferenceID) gDLPIPrivateData->fwUnitID, kMaxTransmitSize);
- }
-
- return (status);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // FWPDriverUnitRemoved
- //
- // FireWire protocol driver interface for handling removed units.
- //
-
- OSStatus FWPDriverUnitRemoved(
- FWPDriverID fwPDriverID,
- UInt32 fwPDriverSpecificData,
- FWUnitID fwUnitID)
- {
- OSStatus status = noErr;
-
- // Clear target unit.
- if ((gDLPIPrivateData->unitConnection) && (gDLPIPrivateData->fwUnitID == fwUnitID))
- {
- FWDeallocateFWCommandObject (gDLPIPrivateData->asynchCommandObjectID);
- FWRemoveUnitConnection (gDLPIPrivateData->fwUnitID, fwPDriverID);
- gDLPIPrivateData->unitConnection = false;
- gDLPIPrivateData->fwUnitID = kInvalidFWUnitID;
- }
-
- return (status);
- }
-
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is used by the driver to validate that our hardware is available.
- // By using the ID we can find out the logical address of the card space (memory or
- // I/O).
- //
- // Next we should check if this driver can work with that card. If the driver can
- // use the card then return kOTNoError. The logical address can be used with
- // C pointers (even for I/O space) since GetPCICardBaseAddress returned a logical
- // address.
- //
- // Keep in mind that even if the dlpi responds with kOTNoError the user may decide
- // to not use your card...so the card state should be in the same state as when
- // the routine was called. In other words, turn off the card before you leave
- // this routine and also deallocate any memory that you allocating. The dlpi
- // may be unloaded from memory so do not expect to have globals between the
- // the ValidateHardware routine and InitStreamModule.
- //
- // Input:
- // theID - node id of the card in the system registry
- //
- // Output:
- // kOTNoError if the hardware is available
- // kENXIOErr, if could not obtain card base address or driver does not work with card
- //
- //-----------------------------------------------------------------------------------------
- OTResult ValidateHardware(RegEntryID *theID)
- {
- OTResult error = kENXIOErr; // default error code
-
-
- error = 0;
-
- return error;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is required and will only be called once. The routine must
- // call OTInitModule(). At this point Open Transport has made the decision to
- // use our card for a network connection. We must save the RegEntryID in case
- // we need it later. We should get the card assigned address and save
- // it in the dlpi private data area. The hw must be initialized and memory
- // allocated for dma buffers, install isrs, ....
- //
- // Open Transport will start calling our open, put, and service routines after
- // this routine if we return true.
- //
- // Input:
- // theID - node id of the card in the system registry
- //
- // Output:
- // true, if initialization was successful
- // false, if initialization failed
- //
- //-----------------------------------------------------------------------------------------
- Boolean InitStreamModule(RegEntryID *theID)
- {
- Boolean initOK;
-
-
- initOK = OTInitModule();
- if (initOK)
- {
- ABCVendorInitialize(theID); // gDLPIPrivateData is set in this routine
-
- if (gDLPIPrivateData == NULL) // was initialization successful?
- {
- initOK = false; // indicate we failed
- OTTerminateModule(); // disconnect ourselves from Open Transport
- }
- }
-
- return initOK;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is required and will only be called when the driver is about to be
- // unloaded. At this point the driver is going away so we should close down
- // the hardware. If we get reopened then the InitStreamModule() will get called
- // again. The routine must call OTTerminateModule().
- //
- // Input:
- // NONE
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void TerminateStreamModule(void)
- {
-
- if (gDLPIPrivateData)
- {
- ABCVendorClose();
- gDLPIPrivateData = NULL;
- }
-
- OTTerminateModule();
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This is the cfm initialization routine. It is not required and is almost a
- // duplication of the InitStreamModule() routine.
- //
- // Input:
- // theInitBlock - block containing various cfm information
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- OSErr InitCFMRoutine(CFragInitBlock *theInitBlock)
- {
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This is the cfm termination routine. It is not required and is almost a
- // duplication of the TerminateStreamModule() routine.
- //
- // Input:
- // NONE
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void TerminateCFMRoutine(void)
- {
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine returns a pointer to the install_info structure. The
- // name of the routine must be "GetOTInstallInfo" because OT loads the
- // the function pointer by name.
- //
- // Input:
- // NONE
- //
- // Output:
- // returns the install_info pointer
- //
- //-----------------------------------------------------------------------------------------
- install_info* GetOTInstallInfo(void)
- {
-
- return &theInstallInformation;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called each time a new stream is created. The
- // stream structure is allocated and then filled in accordingly. The
- // address of the stream is stored in the dlpi private data and in the read
- // queue data slot.
- //
- // Input:
- // q - write queue
- // devp - device number that consists of major and minor
- // genericFlag - not currently used
- // sflag - indicates special open options
- // crp - not currently used
- //
- // Output:
- // kOTNoError, if no problem occurred
- // error, if no memory or the client tried to open as a module instead of dlpi
- //
- //-----------------------------------------------------------------------------------------
- int OpenServiceRoutine(queue_t *q, dev_t *devp, int genericflag, int sflag, cred_t *crp)
- {
- DLPIStream *theStream;
- minor_t minor_number;
-
- if (sflag == MODOPEN) // this is a dlpi not a module
- return(EINVAL);
-
- if (q->q_ptr != NULL) // this must be a reopen, a stream is already attached
- return kOTNoError;
-
-
- if (sflag == CLONEOPEN) // new streams are opened using the clone
- {
-
- if ((theStream = OTAllocMem(sizeof(DLPIStream))) == NULL) // get memory for stream struct
- return(ENOMEM);
-
- bzero(theStream,sizeof( DLPIStream )); // set everything to zero
-
- theStream->bufferTimerMsg = mi_timer_alloc(WR(q),sizeof(UInt32));
- if (theStream->bufferTimerMsg == NULL)
- {
- OTFreeMem(theStream);
- return(ENOMEM);
- }
-
- minor_number = GenerateUniqueMinorDevice();
- *devp = makedevice(getemajor(*devp), minor_number);
-
- // initialize the stream structure
- theStream->readQueue = q;
- theStream->idType = NULL;
- theStream->dlpiState = DL_UNBOUND;
- theStream->streamFlags = NULL;
- theStream->minorDevice = minor_number;
-
- q->q_ptr = (char *)theStream;
- WR(q)->q_ptr = (char *)theStream;
-
- *((UInt32 *)(theStream->bufferTimerMsg->b_rptr)) = NULL;
-
- EnqueueElement(&gDLPIPrivateData->dlpiStreamsQueue,(QElem *)theStream,kBothTxRxInterrupts);
- }
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine closes a stream. All multicast addresses are unregistered and then
- // the memory for the streams structure is deallocated.
- //
- // Input:
- // q - write queue
- // dummy1 - not currently used
- // dummy2 - not currently used
- //
- // Output:
- // always return kOTNoError
- //
- //-----------------------------------------------------------------------------------------
- int CloseServiceRoutine(queue_t *q, int dummy1, cred_t *dummy2)
- {
- DLPIStream *theStream;
- mblk_t *mp;
-
- theStream = (DLPIStream *)q->q_ptr;
-
- if (theStream->idType == kdlpiBufcallType) // remove any buf call
- unbufcall(theStream->timeoutID);
-
- mi_timer_free(theStream->bufferTimerMsg); // allocated in open stream for buffer time outs
-
- // disable all multicasts that this stream has registered
- while ((mp = (mblk_t *)DequeueHead( &theStream->multicastQueue, kBothTxRxInterrupts)) != NULL)
- {
- ABCVendorUnregisterMulticast(mp->b_rptr);
- freemsg(mp);
- }
-
- q->q_ptr = NULL; // clear the stream pointers in the read & write queues
- (WR(q))->q_ptr = NULL;
-
- // remove this stream from our linked list of stream structures
- DequeueElement(&gDLPIPrivateData->dlpiStreamsQueue,(QElem *)theStream,kBothTxRxInterrupts);
- OTFreeMem(theStream); // and finally free the stream storage
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called when someone wants to put something on our write queue.
- // Somethings are handled immediately are some are put on the write queue and
- // then serviced during the write service routine. If a message is received that
- // the driver is not expecting then it is dropped on the floor.
- //
- // Input:
- // q - the write queue
- // mp - message that we need to process
- //
- // Output:
- // returns true
- //
- //-----------------------------------------------------------------------------------------
- int WritePutRoutine(queue_t *q, mblk_t *mp)
- {
- union DL_primitives *dlp;
- UInt32 prim;
- DLPIStream *theStream;
-
- switch (mp->b_datap->db_type)
- {
- case M_IOCTL:
- IOCtlTheStream(q, mp);
- break;
- case M_FLUSH:
- FlushTheStream(q, mp);
- break;
- case M_PCSIG: // timer messages come here
- HandleTimerMessages(q, mp);
- break;
- case M_PROTO:
- case M_PCPROTO:
- dlp = (union DL_primitives *)mp->b_rptr;
- prim = dlp->dl_primitive;
- if (prim == DL_UNITDATA_REQ) // normal transmit packet
- {
- theStream = (DLPIStream *)q->q_ptr;
- DoUnitData(theStream, mp);
- }
- else
- putq(q, mp); // everything else waits until the service routine
- break;
- case M_DATA: // raw packet, just send it out with dlpi manipulation
- PreparePacketToBeSent(mp);
- break;
- case M_COPYIN:
- case M_COPYOUT:
- case M_ERROR:
- case M_HANGUP:
- case M_IOCACK:
- case M_IOCNAK:
- case M_HPDATA:
- case M_STOP:
- case M_START:
- case M_STOPI:
- case M_STARTI:
- case M_READ:
- case M_SETOPTS:
- case M_SIG:
- case M_BREAK:
- case M_DELAY:
- case M_CTL:
- case M_PASSFP:
- case M_RSE:
- default:
- freemsg(mp);
- break;
- }
-
- return(kTrue);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles everything that was deferred (put on the write queue) during
- // the write put routine. This routine is really just a big switch statement to the
- // different routines that handle each message. If a message is not supported
- // then an error ack is sent to the client.
- //
- // Input:
- // q - the write queue
- //
- // Output:
- // returns kOTNoError
- //
- //-----------------------------------------------------------------------------------------
- int WriteServiceRoutine(queue_t *q)
- {
- mblk_t *mp;
- DLPIStream *theStream;
- UInt32 err, prim;
- union DL_primitives *dlp;
-
- if ((theStream = (DLPIStream *)q->q_ptr) == NULL || (gDLPIPrivateData == NULL))
- return kOTNoError;
-
- while ((mp = getq(q)) != NULL) // continue retrieving messages until empty
- {
- err = kOTNoError;
- dlp = (union DL_primitives *)mp->b_rptr;
- prim = dlp->dl_primitive;
- switch (prim)
- {
- case DL_XID_REQ:
- if (DoXID(theStream, mp, 0) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_XID_RES:
- if (DoXID(theStream, mp, 1) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_TEST_REQ:
- if (SendTestPacket(theStream, mp, 0) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_TEST_RES:
- if (SendTestPacket(theStream, mp, 1) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_INFO_REQ:
- if (DoGeneralInfo(theStream) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- else
- freemsg(mp);
- break;
- case DL_SET_PHYS_ADDR_REQ:
- if (DoSetPhysicalAddress(theStream, mp) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_BIND_REQ:
- if (BindTheStream(theStream, mp) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_UNBIND_REQ:
- if (UnBindTheStream(theStream, mp) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_SUBS_BIND_REQ:
- if (SubsBindTheStream(theStream, mp) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_SUBS_UNBIND_REQ:
- if (UnSubsBindTheStream(theStream, mp) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_ENABMULTI_REQ:
- if (DoEnableMulticast(theStream, mp) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_DISABMULTI_REQ:
- if (DoDisableMulticast(theStream, mp) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- case DL_PHYS_ADDR_REQ:
- if (DoPhysicalAddressAck(theStream,mp) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- else
- freemsg(mp);
- break;
- #if 0
- case DL_GET_STATISTICS_REQ:
- if (DoStatisticsAck(theStream,mp) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- else
- freemsg(mp);
- break;
- #endif
- case DL_ATTACH_REQ:
- case DL_DETACH_REQ:
- case DL_PROMISCON_REQ:
- case DL_PROMISCOFF_REQ:
- case DL_UDQOS_REQ:
- case DL_CONNECT_REQ:
- case DL_CONNECT_RES:
- case DL_TOKEN_REQ:
- case DL_DISCONNECT_REQ:
- case DL_RESET_REQ:
- case DL_RESET_RES:
- case DL_DATA_ACK_REQ:
- case DL_REPLY_REQ:
- case DL_REPLY_UPDATE_REQ:
- err = DL_NOTSUPPORTED; // fall through
- default:
- if (err == kOTNoError)
- err = DL_BADPRIM;
- if (DoErrorAck(theStream, mp, prim, err, 0) == kdlpiRETRY)
- {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
- }
- } // while
-
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles all the ioctl calls made to the driver. Currently only
- // the mentat fast call is handled and the framing type.
- //
- // For the Mentat Fastpath...
- // The dlpi is called and then returns a built header for the current stream.
- //
- // For the framing type...
- // If the kOTFraming8022 value is passed in then the general info routine
- // should start returning DL_CSMACD. If that value is not passed in then
- // the general info routine should return DL_ETHER.
- //
- // Input:
- // q - the write queue
- // mp - the message block that contains ioctl parameters
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void IOCtlTheStream(queue_t *q, mblk_t *mp)
- {
- struct iocblk *iocPtr = (struct iocblk *)mp->b_rptr;
- mblk_t *headerMP;
- long temp;
- DLPIStream *theStream;
-
- iocPtr->ioc_count = 0;
- iocPtr->ioc_error = 0;
- iocPtr->ioc_rval = 0;
-
- switch( iocPtr->ioc_cmd )
- {
- case I_OTSetFramingType: // toggles what the general info primitive returns
- headerMP = mp->b_cont; // for dl_mac_type in dl_info_ack_t structure
- mp->b_cont = NULL;
- if ( headerMP == NULL || ((headerMP->b_wptr - headerMP->b_rptr) != sizeof(UInt32)) )
- {
- if (headerMP)
- freemsg(headerMP);
- mp->b_datap->db_type = M_IOCNAK;
- break;
- }
- temp = *(long*)headerMP->b_rptr;
- if ( temp == kOTFraming8022 )
- gDLPIPrivateData->privateFlags |= kpfFraming8022;
- else
- gDLPIPrivateData->privateFlags &= ~kpfFraming8022;
- freemsg(headerMP);
- mp->b_datap->db_type = M_IOCACK;
- break;
-
- case DL_IOC_HDR_INFO: // special Mentat call, for fast transmits
- headerMP = mp->b_cont; // get destination address information
- mp->b_cont = NULL; // disconnect dest addr mb
-
- headerMP = BuildTxPacketHeader((DLPIStream *)q->q_ptr, headerMP, kTrue);
-
- if (headerMP == NULL) // could not allocate a message block large enough
- {
- iocPtr->ioc_error = ENOMEM;
- mp->b_datap->db_type = M_IOCNAK;
- }
- else
- {
- mp->b_cont = headerMP; // hook mb's back together
- mp->b_datap->db_type = M_IOCACK;
- }
-
- break;
-
- case I_OTSetRawMode: // toggles receive raw packet mode
- theStream = (DLPIStream *)q->q_ptr;
- headerMP = mp->b_cont;
- if ((headerMP == NULL) || ((headerMP->b_wptr - headerMP->b_rptr) != sizeof(UInt32)) )
- {
- if (headerMP)
- freemsg(headerMP);
- mp->b_datap->db_type = M_IOCNAK;
- break;
- }
- temp = *(long*)headerMP->b_rptr;
- if ( temp == kOTRawRcvOn )
- {
- theStream->streamFlags |= kReadRawPackets;
- mp->b_datap->db_type = M_IOCACK;
- }
- else
- {
- if ( temp == kOTRawRcvOff )
- {
- theStream->streamFlags &= ~kReadRawPackets;
- mp->b_datap->db_type = M_IOCACK;
- }
- else // message value is unkown to us
- mp->b_datap->db_type = M_IOCNAK;
- }
- break;
-
- default:
- mp->b_datap->db_type = M_IOCNAK;
- break;
- }
-
- qreply(q, mp); // send response back up the stream
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine receives the flush call and then it must send it up the read
- // side of the stream.
- //
- // Input:
- // q - the write queue
- // mp - the message block that contains the flush parameters
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void FlushTheStream(queue_t *q, mblk_t *mp)
- {
- UInt8 *rptr = mp->b_rptr;
-
- if (*rptr & FLUSHW)
- {
- flushq(q, FLUSHALL);
- *rptr &= ~FLUSHW;
- }
-
- if (*rptr & FLUSHR)
- {
- flushq(RD(q), FLUSHALL);
- qreply(q, mp);
- }
- else
- freemsg(mp);
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles timer messages received on a stream. The timer message
- // contains an identifier that we define. Right now the routine only handles
- // one type of timer message.
- //
- // Input:
- // writeQueue - write queue which has been given the timer message
- // mp - the message block that contains the flush parameters
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void HandleTimerMessages(queue_t *writeQueue, mblk_t *mp)
- {
- DLPIStream *theStream;
- Boolean isTimerValid;
- UInt32 timerMsgType;
-
- theStream = (DLPIStream *)writeQueue->q_ptr;
-
- isTimerValid = mi_timer_valid(theStream->bufferTimerMsg);
-
- if (isTimerValid == kFalse)
- return;
-
- timerMsgType = *((UInt32 *)(theStream->bufferTimerMsg->b_rptr));
-
- switch(timerMsgType)
- {
- case kEnableQueueTimerMsg:
- *((UInt32 *)(theStream->bufferTimerMsg->b_rptr)) = NULL;
- qenable(writeQueue);
- break;
- default:
- break;
- }
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine actually transmits the packet out on the wire. If the packet
- // is an 802.3 packet then we must fill in the appropriate length (16 bits) in
- // the Ethernet header. If for some reason the packet cannot be sent when this
- // routine is called then the packet must be kept around until the resources necessary
- // to send the packet are freed up. One way of doing this might involve creating
- // a linked list of packets needing to be sent. The resources will probably be
- // freed up during a transmit interrupt. During the Tx ISR a deferred task is
- // setup to send any packets waiting on the linked list.
- //
- // Input:
- // thePacket - the message block containing the packet to send
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void PreparePacketToBeSent(mblk_t *thePacket)
- {
- EnetPacketHeader *enetHeader;
- UInt16 len;
-
- enetHeader = (EnetPacketHeader *)thePacket->b_rptr;
-
- if (enetHeader->fProto == NULL)
- {
- len = msgdsize(thePacket) - sizeof(EnetPacketHeader);
- enetHeader->fProto = len;
- }
-
- // Fill in the Ethernet source address.
- OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,enetHeader->fSourceAddr);
-
- thePacket->b_next = NULL;
-
- ABCVendorDisableInterrupts(kTxInterrupts);
-
- EnqueueElement(&gDLPIPrivateData->TxPacketQueue, (QElem *)thePacket,kNoInterrupts);
-
- AttemptPacketSend(); // may or may not be able to send the packet
-
- ABCVendorEnableInterrupts(kTxInterrupts);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine checks the tx packet queue to see if any packets are available
- // for transmission. If packets are found then the packet at the head is checked
- // to see if it can fit in the available dma resources. This routine is called by
- // the normal thread of execution PreparePacketToBeSent and also by TxDTCallback.
- // Both times the tx interrupt enable will be turned off because we want to send
- // out as many packets as possible before we have to service the isr. Otherwise
- // we will pop back and forth between this routine and the tx isr which is not as
- // efficient.
- //
- // Input:
- // NONE
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void AttemptPacketSend(void)
- {
-
- OSErr error = kOTNoError;
- UInt16 packetSize;
- mblk_t *thePacket;
-
- while ((error == kOTNoError) && gDLPIPrivateData->TxPacketQueue.qHead)
- {
- packetSize = msgdsize((mblk_t *)gDLPIPrivateData->TxPacketQueue.qHead);
- error = ABCVendorCheckTransmitterStatus(packetSize);
- if (error == kOTNoError)
- {
- thePacket = (mblk_t *)DequeueHead(&gDLPIPrivateData->TxPacketQueue,kNoInterrupts);
- ABCVendorTransmitOnePacket(thePacket,packetSize); // this routine sends the packet
- freemsg(thePacket);
- }
- }
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called by the deferred task manager. If for some reason a packet
- // could not be sent in the put routine and was deferred now would be a good time
- // to send it.
- //
- // Input:
- // theParam - the refcon value for the call back, not used
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
-
- pascal void TxDTCallback(void *theParam)
- {
-
- // try to send any packets on the wait queue
-
- ABCVendorDisableInterrupts(kTxInterrupts);
-
- AttemptPacketSend(); // may or may not be able to send the packet
-
- ABCVendorEnableInterrupts(kTxInterrupts);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called by the deferred task manager. After the essential work
- // has been done in the ISR then this routine should do the bulk of the work.
- //
- // The isr placed the packet (in the form of a message block) on the rx packet
- // queue. It is the responsibility of this routine to dequeue all the packets
- // and pass them on to any clients (streams) that want them.
- //
- // Input:
- // theParam - the refcon value for the call back return
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
-
- pascal void RxDTCallback(void *theParam)
- {
- mblk_t *thePacket;
-
- while ((thePacket = (mblk_t *) DequeueHead(&gDLPIPrivateData->RxPacketQueue, kRxInterrupts))
- != NULL)
- FindStreamForReceivedPacket((DLPIStream *)gDLPIPrivateData->dlpiStreamsQueue.qHead, thePacket);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is used to enqueue an element onto the head of the list.
- // An element is just a structure that has as it's first field a link. The
- // link field is used to connect structures in a linked list. Each list contains
- // items of the same type. The DLPI uses lists to maintain various resources.
- //
- // Input:
- // theQHdr - a system type queue header
- // whichIntsOff - the caller determines which interrupts need to be off
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void EnqueueElementAtHead(QHdr *theQHdr, QElem *theElem, UInt16 whichIntsOff)
- {
-
- ABCVendorDisableInterrupts(whichIntsOff);
-
- if ((theElem->qLink = theQHdr->qHead) != NULL) // is the queue nonzero?
- theQHdr->qHead = theElem;
- else // empty list
- {
- theQHdr->qTail = theElem;
- theElem->qLink = NULL;
- }
-
- ABCVendorEnableInterrupts(whichIntsOff);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine enqueues an element onto the back of the queue.
- // An element is just a structure that has as it's first field a link. The
- // link field is used to connect structures in a linked list. Each list contains
- // items of the same type. The DLPI uses lists to maintain various resources.
- //
- // Input:
- // theQHdr - a system type queue header
- // theElem - the element that should be placed on the queue
- // whichIntsOff - the caller determines which interrupts need to be off
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void EnqueueElement(QHdr *theQHdr, QElem *theElem, UInt16 whichIntsOff)
- {
-
- ABCVendorDisableInterrupts(whichIntsOff);
-
- if (theQHdr->qHead)
- theQHdr->qTail->qLink = theElem;
- else
- theQHdr->qHead = theElem;
-
- theQHdr->qTail = theElem;
- theElem->qLink = NULL;
-
- ABCVendorEnableInterrupts(whichIntsOff);
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine dequeues an element.
- // An element is just a structure that has as it's first field a link. The
- // link field is used to connect structures in a linked list. Each list contains
- // items of the same type. The DLPI uses lists to maintain various resources.
- //
- // Input:
- // theQHdr - a system type queue header
- // theElem - the element that should be removed from the queue
- // whichIntsOff - the caller determines which interrupts need to be off
- //
- // Output:
- // returns the element if it was found on the queue, NULL if the element was
- // not on the queue
- //
- //-----------------------------------------------------------------------------------------
-
- QElem *DequeueElement(QHdr *theQHdr, QElem *theElem, UInt16 whichIntsOff)
- {
- QElem *listWalker,*previousElem;
- Boolean foundMatch = kFalse;
-
- ABCVendorDisableInterrupts(whichIntsOff);
-
- // no elements in the list or null element passed in
- if (((listWalker = theQHdr->qHead) == NULL) || (theElem == NULL))
- {
- ABCVendorEnableInterrupts(whichIntsOff);
- return NULL;
- }
-
- if (theQHdr->qHead == theElem) // only 1 element or/and element is the head
- {
- DequeueHead(theQHdr,whichIntsOff); // interrupts will be enabled by enable
- return theElem; // routine in DequeueHead
- }
-
-
- previousElem = listWalker;
- while (listWalker && (!(listWalker == theElem))) // walk thru list till we find a match
- {
- previousElem = listWalker;
- listWalker = listWalker->qLink;
- }
-
- if (listWalker) // found the element in the list!
- {
- previousElem->qLink = listWalker->qLink; // disconnect element from the queue
- if (theElem == theQHdr->qTail) // was the element the last element on the queue?
- theQHdr->qTail = previousElem;
-
- theElem->qLink = NULL;
- }
- else
- theElem = NULL; // element not in the list
-
- ABCVendorEnableInterrupts(whichIntsOff);
-
- return theElem;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine dequeues the element at the head of the queue.
- // An element is just a structure that has as it's first field a link. The
- // link field is used to connect structures in a linked list. Each list contains
- // items of the same type. The DLPI uses lists to maintain various resources.
- //
- // Input:
- // theQHdr - a system type queue header
- // whichIntsOff - the caller determines which interrupts need to be off
- //
- // Output:
- // returns the element that was at the head or NULL if the queue was empty
- //
- //-----------------------------------------------------------------------------------------
-
- QElem *DequeueHead(QHdr *theQHdr, UInt16 whichIntsOff)
- {
- QElem *theElem;
-
- ABCVendorDisableInterrupts(whichIntsOff);
-
- if (theQHdr->qHead)
- {
- if (theQHdr->qHead == theQHdr->qTail) // only 1 element in the list
- theQHdr->qTail = NULL;
- theElem = theQHdr->qHead;
- theQHdr->qHead = theElem->qLink;
- theElem->qLink = NULL;
- }
- else
- theElem = NULL;
-
- ABCVendorEnableInterrupts(whichIntsOff);
-
- return theElem;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine generates a unique number for the minor device. The last used
- // minor device number is stored in the globals. The value is incremented by
- // 1 and then each stream is checked to make sure it is not in use.
- //
- // Input:
- // NONE
- //
- // Output:
- // returns new minor device number for this driver
- //
- //-----------------------------------------------------------------------------------------
-
- UInt16 GenerateUniqueMinorDevice(void)
- {
- Boolean found;
-
- // start unique number guessing at where we ended last time, we have a possible
- // 64,000 minor numbers, so if we hit ffff we just start at 0 and continue
-
- do {
- found = CheckThisMinorDevice(++gDLPIPrivateData->currentMinorDeviceNumber);
- } while(!found);
-
- return gDLPIPrivateData->currentMinorDeviceNumber;
-
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine checks a minor device number against all the streams. If the
- // minor device number is in use then the routine returns false.
- //
- // Input:
- // minorDeviceNumber - the routine checks this device number against device
- // numbers in existing streams that are attached to this device.
- //
- // Output:
- // true, if minorDeviceNumber is not in use by another streams
- // false, if minorDeviceNumber is in use by another stream
- //
- //-----------------------------------------------------------------------------------------
-
- Boolean CheckThisMinorDevice(UInt16 minorDeviceNumber)
- {
- mblk_t *mbWalker;
- Boolean isUnique = kTrue;
-
- mbWalker = (mblk_t *)gDLPIPrivateData->dlpiStreamsQueue.qHead;
-
- while (mbWalker && isUnique)
- {
- if (((DLPIStream *)mbWalker)->minorDevice == minorDeviceNumber)
- isUnique = kFalse;
- else
- mbWalker = mbWalker->b_next;
- }
-
- return isUnique;
- }
-
-